
#include "sys.h"
#include "mem.h"
#include "sockets.h"
#include "opt.h"

#include "cfg_main.h"
#include "tcpserver.h"

static void tcp_server_thread(void *arg)
{
    s32_t maxFd, i = 0, listener, con;
    struct sockaddr_in serverAddr, clientAddr;

    fd_set master;
    fd_set readFds;

    while (gTaskAllStartCodeFlag != TASK_ALLSTART_RUN)
    {
        OSTimeDly(OS_TICKS_PER_SEC);
    }

P0:
    con  = 0;
    FD_ZERO(&master);
    FD_ZERO(&readFds);

    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(gLinkInfor.localIp.port);
    serverAddr.sin_addr.s_addr = INADDR_ANY;
    memset(&(serverAddr.sin_zero), 8, sizeof(serverAddr.sin_zero));

    if ((listener = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        goto P0;
    }
    if (bind(listener, (struct sockaddr*)&serverAddr, sizeof(struct sockaddr)) == -1)
    {
        lwip_close(listener);
        goto P0;
    }
    if (listen(listener, 1) == -1)
    {
        lwip_close(listener);
        goto P0;
    }

    FD_SET(listener, &master);
    maxFd = listener + 1;

    while (1)
    {
        struct timeval timeout = { 0, 100 * 1000 };

        readFds = master;

        if ( lwip_select(maxFd, &readFds, 0, 0, &timeout) == 0)
        {
            u8_t err;
            GdSuperFrameExtType *msg;

            msg = (void*)OSQPend(LinkEthTxDataMsgQ_S, OS_TICKS_PER_SEC / 1000, &err);
            if (err == OS_NO_ERR)
            {
                if (send(con, (u8_t*)&msg->GdSuperFrame.frame, msg->size, 0) < 0)
                {
                    lwip_close(i);
                    FD_CLR(i, &master);
                }

                gLinkSendState = 0;
                SafeFree(msg);
            }

            continue;
        }

        for (i = 0; i < maxFd; i++)
        {
            if (FD_ISSET(i, &readFds))
            {
                if (i == listener)
                {
                    u32_t sinSize;
                    s32_t connected;

                    sinSize = sizeof(struct sockaddr_in);
                    connected = accept(i, (struct sockaddr*)&clientAddr, &sinSize);
                    if (connected != -1)
                    {
                        FD_SET(connected, &master);
                        if ((connected + 1) > maxFd)
                        {
                            maxFd = connected + 1;
                        }
                        con = connected;
                    }
                }
                else
                {
                    s32_t rxSize;
                    u8_t *recvDataBuff = SafeMalloc(2048);

                    if (recvDataBuff != NULL)
                    {
                        rxSize = recv(i, recvDataBuff, 2048, 0);

                        if (rxSize <= 0)
                        {
                            OS_ENTER_CRITICAL();
                            gLinkInfor.level = LINK_LEVEL_POWER_OFF;
                            if(gLinkInfor.gprsModule == GPRS_MODULE_RF230)
                            {
                                gLinkInfor.channel = LINK_CHANNEL_RF230;
                            }
                            else
                            {
                                gLinkInfor.channel = LINK_CHANNEL_GPRS_TCPC;
                            }
                            OS_EXIT_CRITICAL();

                            SafeFree(recvDataBuff);

                            lwip_close(i);
                            FD_CLR(i, &master);

                            continue;
                        }
                        else
                        {
                            GdSuperFrameExtType *msg = SafeMalloc(rxSize + sizeof(GdSuperFrameExtType));
                            gLinkInfor.channel = LINK_CHANNEL_ETH_TCPS;
                            gLinkInfor.level = LINK_LEVEL_CONNECT;

                            if (msg != NULL)
                            {
                                INT16U tmp = ((rxSize << 8) & 0xFF00);
                                tmp += ((rxSize >> 8) & 0xFF);
                                msg->size = tmp;
                                msg->GdSuperFrame.chl = LINK_CHANNEL_ETH_TCPS;
                                memcpy((u8_t*)&msg->GdSuperFrame.frame, recvDataBuff, rxSize);
                                if (OSQPost(LinkAllRxDataMsgQ, (void*)msg) != OS_NO_ERR)
                                {
                                    SafeFree(msg);
                                }
                            }
                        }

                        SafeFree(recvDataBuff);
                    }
                }
            }
        }
    }
}

void tcp_server_init(void)
{
    sys_thread_new("tcpserver",
                   tcp_server_thread,
                   NULL,
                   LWIP_STK_SIZE,
                   DEFAULT_THREAD_PRIO
                   );
}

